﻿//-----------------------------------------------------------------------
// <copyright file="InputModule.cs" company="Nathan Miller">
// Copyright (c) Nathan Miller.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
//-----------------------------------------------------------------------
namespace App.Modules.Input
{
    using System.Collections.Generic;
    using App.Modules.Editor;
    using App.Modules.Render;
    using App.Modules.Tool;
    using TileTool.Editor.Tool.Scene;
    using TileTool.Input;
    using TileTool.Input.Keyboard;
    using TileTool.Log;
    using TileTool.Render;

    /// <summary>
    /// Application input module.
    /// </summary>
    public class InputModule : Module
    {
        #region Constants - Private

        /// <summary>
        /// Log message group.
        /// </summary>
        private const string LogGroup = "InputModule";

        #endregion

        #region Methods - Public

        /// <summary>
        /// Called when the application is starting up.
        /// </summary>
        public override void Startup()
        {
            LogSystem.LogStartup(LogGroup, "Starting...");

            RenderModule renderModule = GetModule<RenderModule>();
            ICanvas canvas = renderModule.Canvas;

            canvas.Input += this.HandleCanvasInput;

            base.Startup();
        }

        /// <summary>
        /// Called when the application is shutting down.
        /// </summary>
        public override void Shutdown()
        {
            base.Shutdown();
        }

        #endregion

        #region Methods - Private

        /// <summary>
        /// Handle a canvas input event.
        /// </summary>
        /// <param name="canvas">Canvas the input event was on.</param>
        /// <param name="inputData">Input event data.</param>
        private void HandleCanvasInput(ICanvas canvas, InputData inputData)
        {
            if (this.HandleInputTest(canvas, inputData))
            {
                return;
            }

            RenderModule renderModule = GetModule<RenderModule>();
            ToolModule toolModule = GetModule<ToolModule>();
            IList<ISceneTool> sceneToolList = toolModule.SceneTools;
            SceneToolInputData sceneToolInputData = new SceneToolInputData(canvas, renderModule.Camera, inputData);

            for (int i = sceneToolList.Count - 1; i >= 0; --i)
            {
                ISceneTool tool = sceneToolList[i];

                if (tool.HandleInput(sceneToolInputData) == InputHandled.Yes)
                {
                    break;
                }
            }
        }

        /// <summary>
        /// Test function.
        /// </summary>
        /// <param name="canvas">Canvas the input event was on.</param>
        /// <param name="inputData">Input event data.</param>
        /// <returns>Returns true if the input data was handled.</returns>
        private bool HandleInputTest(ICanvas canvas, InputData inputData)
        {
            if (inputData.InputType != InputDataType.Key)
            {
                return false;
            }

            KeyInputData key = (KeyInputData)inputData;
            if (!key.Down)
            {
                return false;
            }

            bool handled = false;

            // $TODO - Ugh this is awful. Write a better input system.
            if (key.Key == InputKey.Q)
            {
                ToolModule toolModule = GetModule<ToolModule>();

                toolModule.ToolManager.UninstallModal();
                handled = true;
            }
            else if (key.Key == InputKey.W)
            {
                ToolModule toolModule = GetModule<ToolModule>();
                toolModule.InstallTool("TranslateTool");
                handled = true;
            }
            else if (key.Key == InputKey.E)
            {
                ToolModule toolModule = GetModule<ToolModule>();
                toolModule.InstallTool("RotateTool");
                handled = true;
            }
            else if (key.Key == InputKey.R)
            {
                ToolModule toolModule = GetModule<ToolModule>();
                toolModule.InstallTool("SizeTool");
                handled = true;
            }
            else if (key.Key == InputKey.S)
            {
                EditorModule editorModule = GetModule<EditorModule>();

                editorModule.ToggleGridSnap();
                handled = true;
            }
            else if (key.Key == InputKey.Delete)
            {
                EditorModule editorModule = GetModule<EditorModule>();

                editorModule.DeleteSelection();
                handled = true;
            }

            return handled;
        }

        #endregion
    }
}
